#pragma once
#include <game/Config.h>
#include <game/services/ScreenSwitcher.h>

#include <Config.h>

#include <memory>
#include <deque>
#include <vector>
#include <stack>
#include <CompilerFeatures.h>

namespace liba {
namespace lib3d {
namespace hard {
class Hardware;
} // namespace hard
} // namespace lib3d
} // namespace liba

ARELLO_GAME_NAMESPACE_DECL_START
namespace flow {
class Manager;
class EntryDefinition;
} // namespace flow

class DebugInfoManager;

class Screen;
class Root;
class ScreenReference;
class ScreenManagerDebugImpl;

class ScreenManager
	: public services::ScreenSwitcher
{
	friend class ScreenManagerDebugImpl;
public:
	ScreenManager();
	virtual ~ScreenManager();

	void SetGame(Root* value);
	void SetFlowManager(flow::Manager* value);

	bool LifeCycle(liba::time_float dt);	
	void render(liba::lib3d::hard::Hardware* hardware, DebugInfoManager* value);
	void Shutdown();
public: // services::ScreenSwitcher
	virtual void SchedulePush(const std::string& exitId) LIBA_OVERRIDE;
	virtual void ScheduleSwitch(const std::string& exitId, bool useLoadingScreen = false) LIBA_OVERRIDE;
	virtual void ScheduleClearAndSwitch(const std::string& exitId, bool useLoadingScreen = false) LIBA_OVERRIDE;
	virtual void ScheduleRestart() LIBA_OVERRIDE;
private:
	typedef std::pair<flow::EntryDefinition*, Screen*> ScreenPair;
	void tryInitialize();
	void switchScreen(ScreenReference* reference, bool useLoadingScreen);
	void clearAndSwitchScreen(ScreenReference* reference, bool useLoadingScreen);
	void pushScreen(ScreenReference* reference);
	void popScreen(ScreenReference* reference);

	Root *game;
	flow::Manager* flowManager;
	std::auto_ptr<Screen> currentScreen;
	flow::EntryDefinition* currentEntry;
	std::stack<ScreenPair> screensStack;
	ScreenManagerDebugImpl* debugImpl;
};


ARELLO_GAME_NAMESPACE_DECL_END